package com.gzy.gameserver;

import java.awt.geom.Point2D;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.util.Set;

import com.gzy.protocol.PlayerProtocol;
import com.sun.sgs.app.AppContext;
import com.sun.sgs.app.ClientSession;
import com.sun.sgs.app.DataManager;
import com.sun.sgs.app.ManagedReference;

public class Magic 
	implements Serializable
{
	/**The version of the serialized form of this class */
	private static final long serialVersionUID = 1L;
	
	protected ManagedReference<Pawn> owner 	= null;
	protected ManagedReference<Pawn> target = null;
	
	protected boolean		m_bStart = false;
	protected boolean		m_bComplete = false;
	protected boolean		m_bCanAttack = false;
	//properties
	public int 		m_id;
	protected byte  m_type = 0;
	protected int 	m_attack_power = 1;
	protected float m_start_time = 0.f;
	protected float m_dispear_time = 0.5f;
	protected float m_distance = 10.f;
	
	//public class magic data
	public static class MagicData
	{
		public int 		m_id;
		public byte		m_type;
		public int 		m_attack_power = 1;
		public float 	m_start_time = 0.f;
		public float 	m_dispear_time = 0.5f;
		public float 	m_distance = 10.f;
		
		public MagicData(){}
	}
	//
	public Magic()
	{
		
	}
	
	public void init()
	{
		float distance = Point2DOp.distance(target.get().getLocation(), owner.get().getLocation());
		if (distance > m_distance)
		{
			Dir2D dir = new Dir2D(Point2DOp.sub(target.get().getLocation(), owner.get().getLocation()));
			Point2D.Float destPos = Point2DOp.add(owner.get().getLocation(), Point2DOp.mut(dir.getDir2D(), distance - this.m_distance + 2.f));
			owner.get().moveTo(destPos, true);
		}
		else
		{
			this.canAttack();
		}
	}
	
	public void set_id(int id)
	{
		this.m_id = id;
	}
	public int get_id()
	{
		return this.m_id;
	}
	public void set_type(byte type)
	{
		this.m_type = type;
	}
	public byte get_type()
	{
		return this.m_type;
	}
	
	public void set_attack_power(int attack_power)
	{
		this.m_attack_power = attack_power;
	}
	public int get_attack_power()
	{
		return this.m_attack_power;
	}

	public void set_start_time(float start_time)
	{
		this.m_start_time = start_time;
	}
	public float get_start_time()
	{
		return this.m_start_time;
	}

	public void set_dispear_time(float dispear_time)
	{
		this.m_dispear_time = dispear_time;
	}
	public float get_dispear_time()
	{
		return this.m_dispear_time;
	}

	public void set_distance(float distance)
	{
		this.m_distance = distance;
	}
	public float get_distance()
	{
		return this.m_distance;
	}

	public static Magic spawn(Pawn owner, Pawn target)
	{
		Magic magic = new Magic();
		magic.setOwner(owner);
		magic.setTarget(target);
		
		return magic;
	}
	
	public boolean getCanAttack()
	{
		return m_bCanAttack;
	}
	
	protected void canAttack()
	{
		this.owner.get().stopMove();
		
		m_bCanAttack = true; 
		ByteBuffer msg = ByteBuffer.allocate(128);
		msg.putShort(PlayerProtocol.NET_PAWN_ATTACK);
		msg.putLong(this.owner.get().getID().getMostSignificantBits());
		msg.putLong(this.owner.get().getID().getLeastSignificantBits());
		msg.putLong(target.get().getID().getMostSignificantBits());
		msg.putLong(target.get().getID().getLeastSignificantBits());
		msg.putInt(m_id);
		msg.flip();
		
		Set<ManagedReference<Pawn>> pawns = this.owner.get().getWorld().getPawns();
		for (ManagedReference<Pawn> pawnRef : pawns)
		{
			Pawn tPawn = pawnRef.get();
			if(tPawn != null)
			{
				tPawn.getSession().send(msg);
			}
		}
	}
	
	public void complete()
	{
		m_bComplete = true;
		int hurtLife = this.m_attack_power+this.owner.get().getAttackPower() - this.target.get().getDefensePower();
		
		this.target.getForUpdate().hurt(hurtLife, this.owner.get());
		
		ByteBuffer buf =  ByteBuffer.allocate(128);
		buf.putShort(PlayerProtocol.NET_MAGIC_RESULT);
		buf.put(this.m_type);
		buf.putLong(this.target.get().getID().getMostSignificantBits());
		buf.putLong(this.target.get().getID().getLeastSignificantBits());
		buf.putInt(hurtLife);
		buf.flip();
		
		Set<ManagedReference<Pawn>> players = this.owner.get().getWorld().getPawns();
		for (ManagedReference<Pawn> playerRef : players)
		{
			Pawn tPawn = playerRef.get();
			ClientSession session = tPawn.getSession();
			if(!this.equals(tPawn) && session != null)
			{
				session.send(buf);
			}
		}
	}

	public void tick(float dt)
	{
		if(m_bComplete)
			return;
		
		if (!m_bCanAttack)
		{
			if (Point2DOp.distanceSQ(owner.get().getLocation(), target.get().getLocation()) <= m_distance*m_distance)
			{
				this.canAttack();
			}
			return;
		}

		m_start_time -= dt;
		if (m_start_time <= 0)
		{
			m_dispear_time -= dt;
			if (m_dispear_time <= 0.5)
			{
				complete();
			}
			else if(!m_bStart)
			{
				m_bStart = true;
			}
			return;
		}
	}

	public boolean shouldDispear()
	{
		return m_dispear_time <= 0 || this.m_bComplete;
	}
	
	public void setOwner(Pawn owner)
	{
		DataManager dataMgr = AppContext.getDataManager();
		
		if (owner == null)
		{
			this.owner = null;
			return;
		}
		this.owner = dataMgr.createReference(owner);
	}
	
	public void setTarget(Pawn target)
	{
		DataManager dataMgr = AppContext.getDataManager();
		
		if (target == null)
		{
			this.target = null;
			return;
		}
		this.target = dataMgr.createReference(target);
	}
}
